package org.taskexecution.taskexecution.application.scheduledTask.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cephr.accountcenter.application.scheduledTask.TaskDefinitionService;
import com.cephr.accountcenter.application.scheduledTask.TaskScheduleService;
import com.cephr.accountcenter.infrastructure.presistent.mapper.scheduledTask.TaskScheduleMapper;
import com.cephr.accountcenter.infrastructure.presistent.po.scheduledTask.TaskDefinition;
import com.cephr.accountcenter.infrastructure.presistent.po.scheduledTask.TaskSchedule;
import com.cephr.accountcenter.infrastructure.presistent.vo.TaskScheduleVO;
import com.cephr.accountcenter.userinterface.request.taskSchedule.TaskScheduleQueryDTO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @author Lydond
 * @description: 任务调度服务实现
 * @create_date: 2025/10/20-15:24
 */
@Service
public class TaskScheduleServiceImpl extends ServiceImpl<TaskScheduleMapper, TaskSchedule> implements TaskScheduleService {

    @Autowired
    private ObjectMapper objectMapper;

    @Resource
    private TaskDefinitionService taskDefinitionService;

    @Resource
    TaskScheduleMapper taskScheduleMapper;

    // 将状态定义为常量或枚举
    private static final int STATUS_PENDING = 0;
    private static final int STATUS_EXECUTING = 3;

    /**
     * 3. 实现 "findDueTasks" 方法
     * (这将被 TaskScanningService 调用)
     */
    @Override
    public List<TaskSchedule> findDueTasks(LocalDateTime now, int limit) {
        // 从数据库取一批候选（可根据实际情况调整乘数）
        int fetchCount = Math.max(limit * 5, limit); // 例如多取 5 倍，减少漏掉高优先级记录的概率
        List<TaskSchedule> candidates = this.lambdaQuery()
                .eq(TaskSchedule::getStatus, STATUS_PENDING)
                .le(TaskSchedule::getScheduledExecTime, now)
                .last("LIMIT " + fetchCount)
                .list();

        if (candidates == null || candidates.isEmpty()) {
            return Collections.emptyList();
        }

        // Java 端排序：priority 降序，然后 scheduledExecTime 升序
        candidates.sort(Comparator
                .comparing(TaskSchedule::getPriority, Comparator.nullsLast(Comparator.reverseOrder()))
                .thenComparing(TaskSchedule::getScheduledExecTime, Comparator.nullsLast(Comparator.naturalOrder()))
        );

        // 截取前 limit 条
        if (candidates.size() <= limit) {
            return candidates;
        }
        return new ArrayList<>(candidates.subList(0, limit));
    }

    /**
     * 4. 实现 "lockTask" (原子更新锁)
     * (这将被 TaskScanningService 调用)
     *
     * @return boolean true 如果成功获取锁, false 如果失败 (被别人抢了)
     */
    @Override
    public boolean lockTask(Long scheduleId) {

        // .update() 方法返回 boolean (或 int，取决于版本)，表示是否更新成功
        return this.lambdaUpdate()
                .eq(TaskSchedule::getScheduleId, scheduleId)
                .eq(TaskSchedule::getStatus, STATUS_PENDING)
                .set(TaskSchedule::getStatus, STATUS_EXECUTING)
                .update();
    }

    /**
     * 5. 实现 "createTask" 方法
     * (这将被外部调用以创建新任务)
     */
    @Override
    public Long createTask(String taskKey, Object taskParams, LocalDateTime scheduledExecTime, String businessId, String ticketId) {
        // 1. 根据 taskKey 查找任务定义
        TaskDefinition def = taskDefinitionService.lambdaQuery()
                .eq(TaskDefinition::getTaskKey, taskKey)
                .one();
        if (def == null) {
            throw new IllegalArgumentException("任务定义未找到，TaskKey: " + taskKey);
        }

        // 2. 序列化参数
        String paramsJson;
        try {
            paramsJson = objectMapper.writeValueAsString(taskParams);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("任务参数序列化失败", e);
        }

        // 3. 构造实体
        TaskSchedule task = new TaskSchedule();
        task.setTaskDefId(def.getTaskDefId());
        task.setBusinessId(businessId);
        task.setScheduledExecTime(scheduledExecTime);
        task.setTaskParams(paramsJson);
        task.setStatus(STATUS_PENDING);
        task.setPriority(0);
        task.setCreateBy(ticketId);
        this.save(task);

        return task.getScheduleId();
    }

    @Override
    public List<TaskScheduleVO> queryTasks(TaskScheduleQueryDTO taskScheduleQueryDTO) {
        return taskScheduleMapper.queryTasks(taskScheduleQueryDTO);
    }
}

